#include <buola/scene/geodes/ccloth.h>
#include <buola/scene/cmesh.h>
#include <buola/scene/cvertexdata.h>
#include <buola/scene/cindexdata.h>
#include <buola/scene/cmeshbuilder.h>
#include <buola/scene/cscene.h>
#include <buola/scene/crendercontext.h>
#include <buola/scene/techniques/cmeshtechnique.h>
#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
#include <BulletSoftBody/btSoftBodyHelpers.h>

namespace buola { namespace scene {

CCloth::CCloth(const std::array<mat::CVec3f,4> &pCorners,double pMass,int pXSegs,int pYSegs)
    :   mCorners(pCorners)
    ,   mMass(pMass)
    ,   mXSegs(pXSegs)
    ,   mYSegs(pYSegs)
    ,   mSoftBody(nullptr)
{
}

CCloth::~CCloth()
{
}

btSoftBody *CCloth::MakeSoftBody(const PScene &pScene)
{
    mSoftBody=btSoftBodyHelpers::CreatePatch(pScene->SoftBodyWorldInfo(),
                                                 btVector3(mCorners[0].x(),mCorners[0].y(),mCorners[0].z()),
                                                 btVector3(mCorners[1].x(),mCorners[1].y(),mCorners[1].z()),
                                                 btVector3(mCorners[3].x(),mCorners[3].y(),mCorners[3].z()),
                                                 btVector3(mCorners[2].x(),mCorners[2].y(),mCorners[2].z()),
                                                 mXSegs,mYSegs,0,true);
    mSoftBody->setTotalMass(mMass);
    mSoftBody->getCollisionShape()->setMargin(0.001);
    mSoftBody->m_cfg.citerations=50;
    mSoftBody->m_cfg.diterations=50;
    mSoftBody->m_cfg.piterations=50;
    return mSoftBody;
}

void CCloth::Render(CRenderContext &pContext)
{
    ///\todo set model matrix if we have the transform stored in the geode instead of some other object
    CMeshTechnique::Get()->Prepare(pContext);

    if(!mVertexData)
    {
        mVertexData.AddField<float>(FIELD_POSITION,3);
        mVertexData.AddField<float>(FIELD_NORMAL,3);
        mVertexData.AddField<float>(FIELD_TEXCOORD,2);
        mVertexData.AddField<uint32_t>(FIELD_BLEND_INDEX,4);
        mVertexData.AddField<float>(FIELD_BLEND_WEIGHTS,4);
        mVertexData.AddField<float>(FIELD_DIFFUSE,4);
        
        mVertexData.Resize(mSoftBody->m_faces.size()*3);//mCloud.size());
    }

    struct ATTRIBUTE_PACKED LVertex
    {
        float x,y,z;
        float xn,yn,zn;
        float u,v;
        uint32_t mIndices[4];
        float mWeights[4];
        float r,g,b,a;
    };

    LVertex *lVertices=mVertexData.Map<LVertex>();
    
    for(int i=0;i<mSoftBody->m_faces.size();i++)
    {
        for(int j=0;j<3;j++)
        {
            lVertices[i*3+j].x=mSoftBody->m_faces[i].m_n[j]->m_x.x();
            lVertices[i*3+j].y=mSoftBody->m_faces[i].m_n[j]->m_x.y();
            lVertices[i*3+j].z=mSoftBody->m_faces[i].m_n[j]->m_x.z();

            lVertices[i*3+j].xn=0;
            lVertices[i*3+j].yn=0;
            lVertices[i*3+j].zn=1;
            
            lVertices[i*3+j].u=0;
            lVertices[i*3+j].v=0;
            
            lVertices[i*3+j].r=0;
            lVertices[i*3+j].g=0;
            lVertices[i*3+j].b=0;
            lVertices[i*3+j].a=1;
        }
    }
    
    mVertexData.Unmap();
    
    gl::vertex_attrib(1,img::CColor(1,0,0));
    glBindBuffer(GL_ARRAY_BUFFER,mVertexData.GetVBO());
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);
    mVertexData.SetVertexAttrib(0,FIELD_POSITION);
    mVertexData.SetVertexAttrib(2,FIELD_NORMAL);
    mVertexData.SetVertexAttrib(3,FIELD_TEXCOORD);
    
    glDrawArrays(GL_TRIANGLES,0,mSoftBody->m_faces.size()*3);
        
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
}

/*namespace gl*/ } /*namespace buola*/ }
